package com.scs.application.config;

import com.scs.application.core.security.StatelessDefaultSubjectFactory;
import com.scs.application.core.utils.CacheUtils;
import com.scs.application.modules.fsd.consts.FsdConst;
import com.scs.application.modules.sys.security.AccessTokenFilter;
import com.scs.application.modules.sys.security.AccessTokenRealm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SubjectDAO;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description： 权限 配置
 */
@Slf4j
@Configuration
public class ShiroConfig {
    @Bean
    public EhCacheManager ehCacheManager(EhCacheManagerFactoryBean factoryBean) {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManager(factoryBean.getObject());

        return cacheManager;
    }

    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(false);
        return sessionManager;
    }

    @Bean
    public StatelessDefaultSubjectFactory statelessDefaultSubjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }

    @Bean
    public AccessTokenRealm tokenRealm(CacheManager cacheManager) {


        AccessTokenRealm accessTokenRealm = new AccessTokenRealm();
        /**
         * 配置缓存的key，{@link org.apache.shiro.realm.AuthenticatingRealm#getAvailableAuthenticationCache}
         */
        accessTokenRealm.setCachingEnabled(true);
        accessTokenRealm.setAuthenticationCachingEnabled(true);
        accessTokenRealm.setAuthorizationCachingEnabled(true);

        if (cacheManager instanceof EhCacheManager) {
            accessTokenRealm.setAuthenticationCacheName(CacheUtils.AUTHENTICATION_CACHE);
            accessTokenRealm.setAuthorizationCacheName(CacheUtils.AUTHORIZATION_CACHE);
        }
//        else if (cacheManager instanceof ShiroRedisCacheManager) {
//            accessTokenRealm.setAuthenticationCacheName(CacheUtils.AUTHENTICATION_CACHE + ":");
//            accessTokenRealm.setAuthorizationCacheName(CacheUtils.AUTHORIZATION_CACHE + ":");
//        }



        return accessTokenRealm;
    }

    @Bean
    public SubjectDAO subjectDAO() {
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();

        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        /**
         * 必须设置为false，否则会调用{@link DefaultSubjectDAO#save(Subject)} 方法，保存到session，导致 {@link org.apache.shiro.subject.support.DisabledSessionException}
         */
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);

        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        return subjectDAO;
    }


    @Bean
    public DefaultWebSecurityManager securityManager(CacheManager cacheManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(tokenRealm(cacheManager));
        securityManager.setSessionManager(sessionManager());
        securityManager.setSubjectFactory(statelessDefaultSubjectFactory());
        securityManager.setSubjectDAO(subjectDAO());
        securityManager.setCacheManager(cacheManager);

        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        Map<String, Filter> filters = new HashMap<>();
        filters.put("tokenFilter", new AccessTokenFilter());
        shiroFilter.setFilters(filters);

        Map<String, String> filterMap = new LinkedHashMap<>();
        //集成cas后，首先添加该规则
        filterMap.put("/**/singleLogin", "anon");//202104
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/druid/**", "anon");
        filterMap.put("/actuator/**", "anon");
        filterMap.put("/**/login", "anon");
        filterMap.put("/**/getLoginIndexResource", "anon");

        filterMap.put("/wx/**", "anon");
        filterMap.put("/ic/zt/**", "anon");
        filterMap.put("/**.ico", "anon");
        filterMap.put("/static/matr-img/**", "anon");
        filterMap.put("/res/**", "anon");
        filterMap.put("/logs/**", "anon");

        //webservice 访问
        filterMap.put("/webservice/**", "anon");
        //websocket 访问
        filterMap.put("/spdsocket", "anon");

        //智能柜过滤
        filterMap.putAll(FsdConst.shiroConfig);

        //智能柜 访问
        filterMap.put("/apiFsd/**", "anon");
        filterMap.put("/apiMock/**", "anon");
        //配置柜子站点
        //filterMap.put("/intelli/config/**", "anon");

        //文件下载
        filterMap.put("/tool/download/**", "anon");
        filterMap.put("/tool/downloadAbfile/**", "anon");
        //RFID打印外部调用接口
        filterMap.put("/spdAms/**", "anon");
        //RFID打印外部调用接口
        filterMap.put("/LMSAms/**", "anon");

        //第三方接口
        filterMap.put("/thirdparty/**", "anon");

        filterMap.put("/**", "tokenFilter");


        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}
